#include "Precompile.h"
#include "LandscapeGenerator.h"

namespace Graphics{
	LandscapeGenerator::LandscapeGenerator(double falloff){
		pow=3;
		sz=(1<<pow)+1;
		diamondSquare(pow,falloff);
		normalize();
		drawImage();
	}

	void LandscapeGenerator::render(RenderContext* context){
		m_vertBuff->setBuffer(context);
		m_indBuff->setBuffer(context);

		context->m_renderSystem->drawIndexed(indCount,0,0);
	}

	double LandscapeGenerator::randf(){
		return ((double)(rand()%20001-10000))/10000;
	}

	void LandscapeGenerator::normalize(){
		double min, max;
		int x, y;

		min=(max=m_heightMap[0][0]);
		for (y=0; y<sz; y++){
			for (x=0; x<sz; x++){
				if (m_heightMap[x][y]>max) max=m_heightMap[x][y];
				if (m_heightMap[x][y]<min) min=m_heightMap[x][y];
			}
		}
		for (y=0; y<sz; y++)
			for (x=0; x<sz; x++)
				m_heightMap[x][y]=(m_heightMap[x][y]-min)/(max-min);
	}

	void LandscapeGenerator::diamondSquare(int n, double falloff){
		double avg, c;
		int ulx, uly, dim;
		int s, i, j, x, y;

		dim=1<<(n-2);
		/* seed the first few array values with reasonable numbers */
		for (j=0; j<5; j++)
			for (i=0; i<5; i++)
				m_heightMap[dim*i][dim*j]=.75+randf()/8;
		/* run the algorithm */
		c=1.0;
		for (s=2; s<n; s++){
		c*=falloff;
		dim=(1<<(n-s));
		for (j=0; j<(1<<s); j++){
			for (i=0; i<(1<<s); i++){
				uly=j*dim;
				ulx=i*dim;
				y=(1<<(n-s-1))+j*(1<<(n-s));
				x=(1<<(n-s-1))+i*(1<<(n-s));
				avg=0;
				avg+=m_heightMap[ulx][uly];
				avg+=m_heightMap[ulx+dim][uly];
				avg+=m_heightMap[ulx][uly+dim];
				avg+=m_heightMap[ulx+dim][uly+dim];
				avg/=4;
				m_heightMap[x][y]=avg+c*randf();
			}
		}
		dim=(1<<(n-s-1));
		for (j=0; j<=(1<<(s+1)); j++)
			for (i=0; i<=(1<<(s+1)); i++) {
				if ((i+j)%2==0) continue;
				y=j*dim;
				x=i*dim;
				avg=0;
				avg+=m_heightMap[(x-dim>=0)?(x-dim):(x-dim+(1<<n))][y];
				avg+=m_heightMap[x][(y-dim>=0)?(y-dim):(y-dim+(1<<n))];
				avg+=m_heightMap[(x+dim<=(1<<n))?(x+dim):(x+dim-(1<<n))][y];
				avg+=m_heightMap[x][(y+dim<=(1<<n))?(y+dim):(y+dim-(1<<n))];
				avg/=4;
				m_heightMap[x][y]=avg+c*randf();
			}
		}
	}

	void LandscapeGenerator::drawImage(){
		int y, x, val;

		for (y=0; y<sz; y++){
			for (x=0; x<sz; x++){
				val=(int)(255*m_heightMap[x][y]);
				if (val>255) val=255;
				if (val<0) val=0;
				m_heightImg[y][4*x]=val;
				m_heightImg[y][4*x+1]=val;
				m_heightImg[y][4*x+2]=val;
				m_heightImg[y][4*x+3]=1;
			}
		}
	}

	void LandscapeGenerator::generateVertexBuffer(){
		float* vertData = new float[sz*sz*8];
		VertexDataPtr data = VertexDataPtr(new VertexData);
		data->m_numVerts = sz*sz;
		data->m_data = vertData;
		data->m_byteSize = sizeof(float)*8;



		m_vertBuff = Graphics::GraphicsFactory::createVertexBuffer(data);
		delete[] vertData;
	}
	
	void LandscapeGenerator::generateIndexBuffer(){
		indCount = (((sz-1)*(sz-1))/4)*6;
		unsigned int *data = new unsigned int[indCount];
		IndexDataPtr indData = IndexDataPtr(new IndexData);
		indData->m_data = data;
		indData->m_numInds = indCount;
		indData->m_byteSize = sizeof(unsigned int);



		m_indBuff = Graphics::GraphicsFactory::createIndexBuffer(indData);
		delete[] data;
	}
}